package cn.echo.ecc.service.impl;

import cn.echo.ecc.constants.RedisConstants;
import cn.echo.ecc.domain.*;
import cn.echo.ecc.dto.RedisSmsDto;
import cn.echo.ecc.dto.RegisterDto;
import cn.echo.ecc.enums.GlobalExceptionCode;
import cn.echo.ecc.feign.LoginService;
import cn.echo.ecc.mapper.UserMapper;
import cn.echo.ecc.properties.UserVariableConstant;
import cn.echo.ecc.result.JSONResult;
import cn.echo.ecc.service.*;
import cn.echo.ecc.util.AssertUtil;
import cn.echo.ecc.util.BitStatesUtils;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author hulan
 * @since 2022-09-23
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private IUserBaseInfoService userBaseInfoService;

    @Autowired
    private IUserAccountService userAccountService;

    @Autowired
    private LoginService loginService;

    @Autowired
    private UserVariableConstant userVariableConstant;

    @Autowired
    private IRecommendCodeService recommendCodeService;

    @Autowired
    private IUserIntegralLogService userIntegralLogService;

    @Autowired
    private IUserGrowLogService userGrowLogService;

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void register(RegisterDto registerDto) {
        String phone = registerDto.getPhone();
        String password = registerDto.getPassword();
        Integer regChannel = registerDto.getRegChannel();
        String smsCode = registerDto.getSmsCode();
        String code = registerDto.getRecommendCode();
        // 1.参数校验，RSA 303
        // 2.手机号拼接业务键从Redis中查询短信验证码
        String phoneCodeKey = String.format(RedisConstants.PHONE_CODE_KEY, phone);
        Object objPhoneCode = redisTemplate.opsForValue().get(phoneCodeKey);
        // 3.判断短信验证码是否为空，是否过期
        AssertUtil.isNotNull(objPhoneCode, GlobalExceptionCode.OUT_TIME_CODE_ERROR);
        // 4.判断验证码是否正确
        RedisSmsDto redisSmsDto = (RedisSmsDto)objPhoneCode;
        AssertUtil.isEquals(redisSmsDto.getCode(),smsCode,GlobalExceptionCode.CODE_ERROR);
        // 5.根据手机号查询用户信息，判断用户是否已经注册
        User user = selectUser(phone);
        AssertUtil.isNull(user,GlobalExceptionCode.USER_EXISTED_ERROR);
        // 6.调用feign接口保存t_login登录信息
        JSONResult jsonResult = saveLogin(phone,password);
        // 7.判断保存结果是否成功，判断结果里面的data是否为空
        AssertUtil.isTrue(jsonResult.isSuccess(),GlobalExceptionCode.USER_SAVE_ERROR);
        AssertUtil.isNotNull(jsonResult.getData(),GlobalExceptionCode.USER_SAVE_ERROR);
        // 8.获取loginId，并进行类型转换
        Long loginId = Long.valueOf(jsonResult.getData().toString());
        // 9.保存t_user用户信息
        Long userId = saveUser(loginId,phone);
        // 10.保存t_user_base_info用户信息
        initUserBaseInfo(userId,regChannel,code);
        // 11.保存t_user_account用户信息
        initUserAccount(userId);
        if (code != null) {
            // 12.给推荐人送积分和成长值
            senIntegralAndGrow(code);
            // 13.保存送积分日志t_user_integral_log
            saveUserIntegralLog(userId);
            // 14.保存送成长值日志t_user_grow_log
            saveUserGrowLog(userId);
            // 15.删除推荐码
            recommendCodeService.deleteByCode(code);
        }
        // 16.注册成功后从Redis中删除短信验证码
        redisTemplate.delete(phoneCodeKey);

    }

    /**
     * 给推荐人送积分和成长值
     * @param code
     */
    private void senIntegralAndGrow(String code) {
        RecommendCode recommendCode = recommendCodeService.getRecommendCodeByCode(code);
        UserBaseInfo userBaseInfo = userBaseInfoService.selectById(recommendCode.getUserId());
        userBaseInfo.setGrowScore(userBaseInfo.getGrowScore() + userVariableConstant.getRegistered_points());
        userBaseInfo.setIntegral(userBaseInfo.getIntegral() + userVariableConstant.getRegistered_points());
        userBaseInfoService.updateById(userBaseInfo);
    }

    /**
     * 保存送成长值日志t_user_grow_log
     * @param userId
     */
    private void saveUserGrowLog(Long userId) {
        UserGrowLog userGrowLog = new UserGrowLog();
        userGrowLog.setCreateTime(new Date().getTime());
        userGrowLog.setFromReason(userVariableConstant.getFromreason());
        userGrowLog.setScore(userVariableConstant.getRegistered_points());
        userGrowLog.setUserId(userId);
        userGrowLogService.insert(userGrowLog);
    }

    /**
     * 保存送积分日志t_user_integral_log
     * @param userId
     */
    private void saveUserIntegralLog(Long userId) {
        UserIntegralLog userIntegralLog = new UserIntegralLog();
        userIntegralLog.setUserId(userId);
        userIntegralLog.setCreateTime(new Date());
        userIntegralLog.setFromReason(userVariableConstant.getFromreason());
        userIntegralLog.setIntegral(userVariableConstant.getRegistered_points());
        userIntegralLogService.insert(userIntegralLog);
    }

    /**
     * 保存t_user_account用户信息
     * @param userId
     */
    private void initUserAccount(Long userId) {
        UserAccount userAccount = new UserAccount();
        userAccount.setId(userId);
        userAccount.setCreateTime(new Date().getTime());
        userAccount.setFrozenAmount(userVariableConstant.getFrozen_amount());
        userAccount.setUsableAmount(userVariableConstant.getUsable_amount());
        userAccount.setPassword(userVariableConstant.getInit_password());
        userAccountService.insert(userAccount);
    }

    /**
     * 保存t_user_base_info用户信息
     * @param userId
     * @param regChannel
     */
    private void initUserBaseInfo(Long userId, Integer regChannel, String code) {
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setId(userId);
        userBaseInfo.setCreateTime(new Date().getTime());
        userBaseInfo.setRegChannel(regChannel);
        RecommendCode recommendCode = recommendCodeService.getRecommendCodeByCode(code);
        userBaseInfo.setReferId(recommendCode.getUserId());
        userBaseInfoService.insert(userBaseInfo);
    }

    /**
     * 保存t_user用户信息
     * @param loginId
     * @param phone
     * @return
     */
    private Long saveUser(Long loginId, String phone) {
        User user = new User();
        user.setCreateTime(new Date().getTime());
        user.setNickName(phone);
        user.setPhone(phone);
        user.setLoginId(loginId);
        long state = BitStatesUtils.addState(BitStatesUtils.OP_REGISTED, BitStatesUtils.OP_ACTIVED);
        long bitState = BitStatesUtils.addState(state, BitStatesUtils.OP_AUTHED_PHONE);
        user.setBitState(bitState);
        insert(user);
        return user.getId();
    }

    /**
     * 保存t_login登录信息
     * @param phone
     * @param password
     * @return
     */
    private JSONResult saveLogin(String phone, String password) {
        Login login = new Login();
        login.setUsername(phone);
        login.setPassword(password);
        login.setType(Login.USER_TYPE);
        login.setEnabled(Login.ENABLED);
        return loginService.saveOrUpdate(login);
    }

    /**
     * 查询用户信息
     * @param phone
     * @return
     */
    private User selectUser(String phone) {
        Wrapper<User> wrapper = new EntityWrapper<>();
        wrapper.eq("phone",phone);
        return selectOne(wrapper);
    }

    public List<User> listUser(Object[] ids) {
        Wrapper<User> wrapper = new EntityWrapper<>();
        wrapper.in("id",ids);
        return selectList(wrapper);
    }

}
